package behavior_analysis_ui;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingConstants;
import javax.swing.filechooser.FileNameExtensionFilter;

import behavior_analysis_control.DialogErrorException;
import behavior_analysis_control.FileUtils;
import behavior_analysis_control.POIFinder;
import behavior_analysis_control.TrackUtils;
import behavior_analysis_model.Analyzer;
import behavior_analysis_model.MapGenerator;
import behavior_analysis_model.Progress;
import behavior_analysis_model.Track;

/**
 * Thread for Behavior Analysis GUI
 * 
 * @author Fang Liu
 * 
 */
public final class BA_Swing extends JFrame {
	/**
	 * 
	 */
	private static final long serialVersionUID = -6343484812294145003L;

	/**
	 * 
	 */
	private static final String TRACK_FILE_LABEL = "Current track file: ";

	/**
	 * 
	 */
	private static final String NO_FILE = "No file selected.";

	/**
	 * Track list.
	 */
	private final List<Track> my_tracks;

	/**
	 * Open button.
	 */
	JButton my_fileButton;

	/**
	 * Analyze button.
	 */
	JButton my_analyzeButton;

	/**
	 * Track file.
	 */
	final JLabel my_fileLabel;

	/**
	 * Indicator label.
	 */
	final JLabel my_indicatorLabel;

	/**
	 * Progress bar.
	 */
	final JProgressBar my_progressBar;

	/**
	 * Track file.
	 */
	String my_trackFile;

	/**
	 * Loading track file or analyzing.
	 */
	boolean my_loadTrack;

	/**
	 * The main method, invokes the Behavior Analysis program. Command line
	 * arguments are ignored.
	 * 
	 * @param the_args
	 *            -- command line arguments.
	 */
	public static void main(final String... the_args) {
		final BA_Swing gui = new BA_Swing();
		gui.start();
	}

	/**
	 * Constructor.
	 */
	public BA_Swing() {
		my_tracks = new ArrayList<Track>();
		my_fileLabel = new JLabel(NO_FILE);
		my_indicatorLabel = new JLabel("");
		my_progressBar = new JProgressBar(1, 100);
	}

	/**
	 * A method to set up components including panels, buttons and functions.
	 */
	private void setupComponents() {

		final JPanel main_panel = new JPanel(new BorderLayout());

		final JFileChooser fc = new JFileChooser();
		fc.setFileFilter(new FileNameExtensionFilter("Track CSV files (*.csv)",
				"csv"));
		fc.setMultiSelectionEnabled(false);
		fc.setCurrentDirectory(new File("."));
		final BA_Swing frame = this;

		// Set up upper panel
		final JPanel upper_panel = new JPanel(new BorderLayout());

		my_fileButton = new JButton("Open");
		my_fileButton.setMnemonic('O');

		my_fileButton.addActionListener(new ActionListener() {
			public void actionPerformed(final ActionEvent the_event) {
				if (fc.showOpenDialog(frame) == JFileChooser.APPROVE_OPTION) {
					final File file = fc.getSelectedFile();
					my_fileLabel.setText(TRACK_FILE_LABEL
							+ file.getAbsolutePath());
					frame.my_indicatorLabel.setText("");
					my_analyzeButton.setEnabled(true);
				}
			}
		});

		my_fileLabel.setPreferredSize(new Dimension(500, 15));
		my_fileLabel.setHorizontalAlignment(SwingConstants.CENTER);
		upper_panel.add(bufferPanel(my_fileButton), BorderLayout.CENTER);
		upper_panel.add(bufferPanel(my_fileLabel), BorderLayout.SOUTH);

		main_panel.add(upper_panel, BorderLayout.NORTH);

		// Set up upper panel
		final JPanel central_panel = new JPanel(new BorderLayout());
		my_progressBar.setPreferredSize(new Dimension(400, 30));
		my_indicatorLabel.setPreferredSize(new Dimension(500, 15));
		my_indicatorLabel.setHorizontalAlignment(SwingConstants.CENTER);
		central_panel.add(bufferPanel(my_progressBar), BorderLayout.CENTER);
		central_panel.add(bufferPanel(my_indicatorLabel), BorderLayout.SOUTH);
		main_panel.add(central_panel, BorderLayout.CENTER);

		// Set up lower panel
		my_analyzeButton = new JButton("Analyze");
		my_analyzeButton.setEnabled(false);
		my_analyzeButton.setMnemonic('A');
		my_analyzeButton.addActionListener(new ActionListener() {
			public void actionPerformed(final ActionEvent the_event) {
				final File file = fc.getSelectedFile();
				if (file == null) {
					JOptionPane.showMessageDialog(frame,
							"No track file selected!");
					return;
				}

				frame.my_indicatorLabel.setText("Analying file "
						+ fc.getSelectedFile().getAbsolutePath() + " ...");

				my_trackFile = fc.getSelectedFile().getAbsolutePath();
				// frame.analyzeTrack(fc.getSelectedFile().getAbsolutePath());
				my_analyzeButton.setEnabled(false);
				new Thread(new WorkThread()).start();
			}
		});

		main_panel.add(bufferPanel(my_analyzeButton), BorderLayout.SOUTH);
		pack();
		add(main_panel);
	}

	private Component bufferPanel(final JComponent the_comp) {
		final JPanel buffer = new JPanel();
		buffer.setLayout(new FlowLayout());
		buffer.add(the_comp);
		return buffer;
	}

	/**
	 * Analyze track.
	 */
	private boolean analyzeTrack(final String filename, final Progress progress) {
		// Validate CSV file.
		try {
			FileUtils.validateFile(filename);
		} catch (final DialogErrorException ex) {
			JOptionPane.showMessageDialog(this, ex.getMessage());
			return false;
		}
		
		String extention;
		try {
			extention = FileUtils.getExtension(filename);
		} catch (final DialogErrorException ex) {
			JOptionPane.showMessageDialog(this, ex.getMessage());
			return false;
		}

		if (extention.equals("csv")) {
			// Read file to Track objects
			my_tracks.clear();
			try {
				TrackUtils.CSVToTracks(filename, my_tracks, progress);
				my_loadTrack = true;
			} catch (final DialogErrorException ex) {
				JOptionPane.showMessageDialog(this, ex.getMessage());
			}
		} else if (extention.equals("gpx")) {
			// my_tracks.addAll(TrackUtils.GPXToTracks(file_name));
		} else {
			JOptionPane.showMessageDialog(this, "You have chosen a ."
					+ extention + " file." + " Please choose a valid file.");
		}

		my_loadTrack = false;
		final Analyzer analyzer = new Analyzer();
		analyzer.analyzeTracks(my_tracks, progress);

		final ArrayList<Track> pois = new ArrayList<Track>();
		
		try {
			pois.addAll(analyzer.getPOIs().keySet());
		} catch (DialogErrorException e1) {
			JOptionPane.showMessageDialog(this, e1.getMessage());
		}

		final POIFinder pf = new POIFinder(pois);
		
		final MapGenerator mg = new MapGenerator();
		try {
			mg.createFile(pf);
		} catch (final DialogErrorException e) {
			JOptionPane.showMessageDialog(this, e.getMessage());
		}

		finally {
			mg.openURI();
			my_loadTrack = false;
		}

		return true;
	}

	/**
	 * A method calls other methods to create various parts of the user
	 * interface (buttons, panels), set up event handlers, etc.
	 */
	public void start() {
		// javax.swing.JOptionPane.showMessageDialog(null,
		// "SnapShop placeholder");
		setTitle("Behavior Analyzer");
		setResizable(true);
		setLocationRelativeTo(null); // centered
		setupComponents();
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		pack();
		setVisible(true);
	}

	public void reset() {
		my_analyzeButton.setEnabled(false);
		my_indicatorLabel.setText("");
		my_fileLabel.setText(NO_FILE);
		my_progressBar.setValue(0);
	}

	/**
	 * Implementation of Progress interface
	 * 
	 */
	private class MyProgress implements Progress {
		public void setProgress(int i) {
			if (my_loadTrack) {
				my_progressBar.setValue(i / 2);
			} else {
				// analyzing
				my_progressBar.setValue(i / 2 + 50);
			}
			my_progressBar.repaint();
		}
	}

	/**
	 * Class for the working thread
	 * 
	 */
	private class WorkThread implements Runnable {
		public void run() {
			Progress progress = new MyProgress();
			analyzeTrack(my_trackFile, progress);
			my_indicatorLabel.setText("Analyze done!");
			progress.setProgress(100);
			try {
				Thread.sleep(2000); // wait to reset for 2 seconds
			} catch (final InterruptedException e) {
				// do nothing
			}
			reset();
		}
	}
}
